package com.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.DbRuntimeException;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wms.dto.WarehouseOperationsReqDto;
import com.wms.exception.FailureException;
import com.wms.mapper.*;
import com.wms.pojo.*;
import com.wms.service.WarehouseOperationsDetailsService;
import com.wms.service.WarehouseOperationsService;
import com.wms.service.WarehousingEntryUpService;
import com.wms.utils.UserContext;
import com.wms.vo.WarehouseOperationsDetailsResVo;
import com.wms.vo.WarehouseOperationsResVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * @author Yzxxn
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WarehouseOperationsServiceImpl extends ServiceImpl<WarehouseOperationsMapper, WarehouseOperations> implements WarehouseOperationsService {
    private final WarehouseOperationsDetailsService warehouseOperationsDetailsService;
    private final ItemSkuMapper skuMapper;
    private final WarehousingEntryUpService entryUpService;
    private final WarehouseAreaLocalMapper warehouseAreaLocalMapper;
    private final WarehouseAreaMapper warehouseAreaMapper;
    private final WarehouseMapper warehouseMapper;

    @Transactional
    @Override
    public void addOperation(WarehouseOperationsReqDto dto) {
        //参数检验
        if (ObjectUtil.isEmpty(dto)) {
            throw new FailureException("请求参数不能为空");
        }
        if (CollUtil.isEmpty(dto.getTargets()) || CollUtil.isEmpty(dto.getSources())) {
            throw new FailureException("请求参数不全");
        }
        if (dto.getCategory() == 1 && dto.getSources().size() > 1) {
            throw new FailureException("拆分加工来源不能超过1");
        }
        //生成作业单号
        //时间条件构建
        LocalDate today = LocalDate.now();
        LocalDateTime startOfDay = today.atStartOfDay();
        LocalDateTime endOfDay = today.plusDays(1).atStartOfDay();
        Long count = baseMapper.selectCount(Wrappers.<WarehouseOperations>lambdaQuery().ge(WarehouseOperations::getCreateTime, startOfDay).lt(WarehouseOperations::getCreateTime, endOfDay));
        String cc = StrUtil.fillBefore(count.toString(), '0', 4);
        String jobCode = LocalDateTimeUtil.format(LocalDateTime.now(), "yyyyMMdd") + "-" + cc;
        //构建新增对象
        WarehouseOperations operation = WarehouseOperations.builder()
                .jobCode(jobCode)
                .category(dto.getCategory())
                .status(1)
                .empId(UserContext.getUserId())
                .createTime(LocalDateTime.now())
                .build();
        boolean save = save(operation);
        if (!save) {
            throw new DbRuntimeException("仓内作业数据添加失败");
        }
        //详情表新增对象构建
        //来源
        List<WarehouseOperationsDetails> sources = getDetailsList(dto.getSources(), operation, 1);
        //目标
        List<WarehouseOperationsDetails> targets = getDetailsList(dto.getTargets(), operation, 2);
        //详情表数据添加
        boolean sb1 = warehouseOperationsDetailsService.saveBatch(sources);
        boolean sb2 = warehouseOperationsDetailsService.saveBatch(targets);
        if (!sb1 || !sb2) {
            throw new DbRuntimeException("仓内作业详情添加失败");
        }
    }

    /**
     * 处理目标、来源对象
     *
     * @param dto
     * @param operation
     * @param category
     * @return
     */
    private List<WarehouseOperationsDetails> getDetailsList(List<WarehouseOperationsDetails> dto, WarehouseOperations operation, int category) {
        List<WarehouseOperationsDetails> sources = dto;
        Set<Long> sourceSkuIds = sources.stream().map(WarehouseOperationsDetails::getSkuId).collect(Collectors.toSet());
        Map<Long, Double> sourceSkuPriceMap = skuMapper.selectByIds(sourceSkuIds)
                .stream()
                .collect(Collectors.toMap(item -> Long.valueOf(item.getId()), item -> Double.parseDouble(item.getPrice().toString())));
        sources.forEach(details -> {
            details.setWarehouseOperationsId(operation.getId());
            details.setPrice(sourceSkuPriceMap.get(details.getSkuId()));
            details.setCategory(category);
        });
        return sources;
    }

    @Override
    public PageResult getOperationsByPage(String jobCode, Integer status, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        Page<WarehouseOperations> p = (Page<WarehouseOperations>) baseMapper.selectList(Wrappers.<WarehouseOperations>lambdaQuery()
                .like(ObjectUtil.isNotEmpty(jobCode), WarehouseOperations::getJobCode, jobCode)
                .eq(ObjectUtil.isNotEmpty(status), WarehouseOperations::getStatus, status)
                .orderByDesc(WarehouseOperations::getCreateTime));
        log.info(p.getResult().toString());
        return new PageResult(p.getTotal(), p.getResult());
    }

    @Override
    public WarehouseOperationsResVo queryDetails(Long id) {
        WarehouseOperations operation = getById(id);
        // 未确认仓内作业
        List<WarehouseOperationsDetails> sources = getDetails(id, 1);
        // 已确认仓内作业
        List<WarehouseOperationsDetails> targets = getDetails(id, 2);
        WarehouseOperationsResVo vo = new WarehouseOperationsResVo();
        vo.setId(id);
        vo.setCategory(operation.getCategory());
        List<WarehouseOperationsDetailsResVo> sourceList = getDetailsResVos(sources);
        List<WarehouseOperationsDetailsResVo> targetList = getDetailsResVos(targets);
        vo.setSources(sourceList);
        vo.setTargets(targetList);
        return vo;
    }

    /**
     * 对对应的详情对象进行数据操作转换
     *
     * @param targets
     * @return
     */
    private List<WarehouseOperationsDetailsResVo> getDetailsResVos(List<WarehouseOperationsDetails> targets) {
        List<WarehouseOperationsDetailsResVo> targetList = targets.stream().map(details -> {
            WarehouseOperationsDetailsResVo resVo = BeanUtil.toBean(details, WarehouseOperationsDetailsResVo.class);
            ItemSku itemSku = skuMapper.selectById(details.getSkuId());
            resVo.setTitle(itemSku.getTitle());
            resVo.setCode(itemSku.getCode());
            resVo.setPrice(Double.parseDouble(itemSku.getPrice().toString()));
            resVo.setRealPrice(Double.parseDouble(itemSku.getRealPrice().toString()));
            resVo.setProductHeight(itemSku.getProductHeight());
            resVo.setProductLength(itemSku.getProductLength());
            resVo.setProductWidth(itemSku.getProductWidth());
            resVo.setProductWeight(itemSku.getProductWeight());
            resVo.setProductVolume(itemSku.getProductVolume());
            WarehouseAreaLocal local = warehouseAreaLocalMapper.selectById(details.getTargetWarehouseAreaLocaId());
            resVo.setTargetWarehouseAreaLocaCode(local.getLocalCode());
            WarehouseArea warehouseArea = warehouseAreaMapper.selectById(local.getWarehouseAreaId());
            resVo.setTargetWarehouseAreaName(warehouseArea.getName());
            Warehouse warehouse = warehouseMapper.selectById(warehouseArea.getWarehouseId());
            resVo.setTargetWarehouseName(warehouse.getName());
            return resVo;
        }).toList();
        return targetList;
    }

    /**
     * 获取仓内作业（未确认、已确认)列表
     *
     * @param id
     * @param i
     * @return
     */
    private List<WarehouseOperationsDetails> getDetails(Long id, int i) {
        List<WarehouseOperationsDetails> sources = warehouseOperationsDetailsService.list(Wrappers.<WarehouseOperationsDetails>lambdaQuery()
                .eq(WarehouseOperationsDetails::getWarehouseOperationsId, id)
                .eq(WarehouseOperationsDetails::getCategory, i)
        );
        return sources;
    }

    @Override
    public void confirm(Long id) {
        WarehouseOperations operations = getById(id);
        if (operations.getStatus() != 1) {
            throw new FailureException("当前状态禁止确认");
        }
        operations.setStatus(2);
        operations.setUpdateTime(LocalDateTime.now());
        boolean b = updateById(operations);
        if (!b) {
            throw new DbRuntimeException("状态修改失败");
        }
    }


    @Override
    public void adjust(Long id) {
        lambdaUpdate()
                .eq(WarehouseOperations::getId,id)
                .set(WarehouseOperations::getStatus,3)
                .update();
    }


    @Override
    public void deleteOperation(Long id) {
        WarehouseOperations operation = getById(id);
        if (operation.getStatus() != 1) {
            throw new FailureException("当前状态禁止删除");
        }
        boolean b = remove(Wrappers.<WarehouseOperations>lambdaQuery().eq(WarehouseOperations::getId, id).eq(WarehouseOperations::getStatus, 1));
        boolean b1 = warehouseOperationsDetailsService.remove(Wrappers.<WarehouseOperationsDetails>lambdaQuery()
                .eq(WarehouseOperationsDetails::getWarehouseOperationsId, id));
        if (!b || !b1) {
            throw new FailureException("删除失败");
        }
    }
}
